package lib.quasar.widget.chart;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.os.Vibrator;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import lib.quasar.util.ToastUtil;
import lib.quasar.widget.R;
import lib.quasar.widget.chart.draw.DrawAssay;
import lib.quasar.widget.chart.draw.DrawBloodpressure;
import lib.quasar.widget.chart.draw.DrawBloodsugar;
import lib.quasar.widget.chart.draw.DrawHeartrate;
import lib.quasar.widget.chart.draw.DrawNull;
import lib.quasar.widget.chart.draw.DrawTemperature;
import lib.quasar.widget.chart.draw.DrawUrinevolume;
import lib.quasar.widget.chart.draw.IDraw;
import lib.quasar.widget.chart.entry.Entry;

import static android.content.Context.VIBRATOR_SERVICE;

/**
 * description: 图表
 * created by kalu on 2017/11/9 0:42
 */
public final class ChartView extends View {

    private final String mHintLoad = getResources().getString(R.string.chart_load);
    private String mHintText = mHintLoad;

    public static int DRAW_NULL = 0;
    public static int DRAW_TEMPERATURE = 1;
    public static int DRAW_BLOODPRESSURE = 2;
    public static int DRAW_URINEVOLUME = 3;
    public static int DRAW_BLOODGLUCOSE = 4;
    public static int DRAW_HEARTRATE = 5;
    public static int DRAW_ASSAY = 6;

    /**********************************************************************************************/

    private int model = DRAW_NULL;
    private final float[] mTouch = new float[]{-1f, -1f};
    private IDraw mDraw = null;

    /**********************************************************************************************/

    public ChartView(Context context) {
        this(context, null);
    }

    public ChartView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ChartView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        TypedArray array = null;

        try {

            array = getContext().obtainStyledAttributes(attrs, R.styleable.ChartView);
            model = array.getInt(R.styleable.ChartView_cv_model, ChartView.DRAW_NULL);

        } catch (Exception e) {
            e.printStackTrace();
        } finally {

            if (null == array) return;
            array.recycle();
        }
    }

    /**********************************************************************************************/

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);

        final int left = getPaddingLeft();
        final int top = getPaddingTop();
        final int right = w - getPaddingRight();
        final int bottom = h - getPaddingBottom();

        final float width = right - left;
        final float height = bottom - top;
        final float centerX = width / 2f;
        final float centerY = height / 2f;

        final float marginLeft = dp2px(30f);
        final float marginRight = dp2px(20f);
        final float marginTop = dp2px(20f);
        final float marginBottom = dp2px(20f);

        final float paddingLeft = dp2px(0f);
        final float paddingTop = dp2px(0f);
        final float paddingRight = dp2px(0f);
        final float paddingBottom = dp2px(0f);

        if (model == ChartView.DRAW_ASSAY) {
            mDraw = new DrawAssay();
        } else if (model == ChartView.DRAW_TEMPERATURE) {
            mDraw = new DrawTemperature();
        } else if (model == ChartView.DRAW_BLOODPRESSURE) {
            mDraw = new DrawBloodpressure();
        } else if (model == ChartView.DRAW_URINEVOLUME) {
            mDraw = new DrawUrinevolume();
        } else if (model == ChartView.DRAW_HEARTRATE) {
            mDraw = new DrawHeartrate();
        } else if (model == ChartView.DRAW_BLOODGLUCOSE) {
            mDraw = new DrawBloodsugar();
        } else {
            mDraw = new DrawNull();
        }

        if (null != mDraw) {
            mDraw.onDrawInit(left, top, right, bottom,
                    marginLeft, marginTop, marginRight, marginBottom,
                    paddingLeft, paddingTop, paddingRight, paddingBottom,
                    width, height, centerX, centerY, model);
        }

        // IDE预览模式下, 添加测试数据
        if (!isInEditMode()) return;
//        final ArrayList<Entry> entries = EntryManagerTest.parseKLineData(EntryManagerTest.KLINE);
//        addDataSetChanged(entries);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        if (null == mDraw) return;
        if (null == mEntryList || mEntryList.size() == 0) {
            mDraw.onDrawNull(getContext().getApplicationContext(), this, canvas, mHintText, model);
        } else {
            mDraw.onDrawData(getContext().getApplicationContext(), this, canvas, mTouch[0], mTouch[1], model);
        }
    }

    /**************************************************************************************/

    @Override
    public boolean onTouchEvent(MotionEvent e) {

        if (model == DRAW_URINEVOLUME) return true;
        mSimpleOnGestureListener.onTouchEvent(e);
        mSimpleOnScaleGestureListener.onTouchEvent(e);

        switch (e.getAction()) {
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_POINTER_DOWN:
                break;
            case MotionEvent.ACTION_MOVE:
            case MotionEvent.ACTION_HOVER_MOVE:
                if (mTouch[0] == -1 || mTouch[1] == -1f) break;
                mTouch[0] = e.getX();
                mTouch[1] = e.getY();
                postInvalidate();
                getParent().requestDisallowInterceptTouchEvent(true);
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL: {
                mTouch[0] = -1f;
                mTouch[1] = -1f;
                postInvalidate();
                getParent().requestDisallowInterceptTouchEvent(false);
                break;
            }
        }
        return true;
    }

    @Override
    protected void onDetachedFromWindow() {
        resetData();
        super.onDetachedFromWindow();
    }

    public void setHintText(String str) {
        mHintText = str;
        postInvalidate();
    }

    public void setModel(int model){
        this.model = model;
    }

    public void clearList() {
        mEntryList = null;
    }

    /**********************************************************************************************/

    private final Vibrator mVibrator = (Vibrator) getContext().getSystemService(VIBRATOR_SERVICE);
    private float scaleFactorCount = 0;
    private final ScaleGestureDetector mSimpleOnScaleGestureListener = new ScaleGestureDetector(getContext(), new ScaleGestureDetector.SimpleOnScaleGestureListener() {

        @Override
        public boolean onScale(ScaleGestureDetector detector) {

            if (isEmpty()) return true;

            float scaleFactor = detector.getScaleFactor();

            if (scaleFactor < 1) {

                if (isMax()) {
                    scaleFactorCount = 0;
                   // ToastUtil.showToast("不能再放大了");
                } else {
                    scaleFactorCount += scaleFactor;
                    if (scaleFactorCount <= 10) return true;
                    addDot();
                    scaleFactorCount = 0;
                    mVibrator.vibrate(10);
                    postInvalidate();
                }
            } else if (scaleFactor > 1) {

                if (isMin()) {
                    scaleFactorCount = 0;
                  //  ToastUtil.showToast("不能再缩小了");
                } else {
                    scaleFactorCount += scaleFactor;
                    if (scaleFactorCount <= 10) return true;
                    delDot();
                    scaleFactorCount = 0;
                    mVibrator.vibrate(10);
                    postInvalidate();
                }
            }
            return true;
        }
    });
    private float distanceXCount = 0;
    private final GestureDetector mSimpleOnGestureListener = new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener() {

        @Override
        public void onLongPress(MotionEvent e) {

            mVibrator.vibrate(25);
            mTouch[0] = e.getX();
            mTouch[1] = e.getY();
            getParent().requestDisallowInterceptTouchEvent(true);
            postInvalidate();
        }

        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {

            if (e1.getPointerCount() != 1 || e2.getPointerCount() != 1) return false;

            if (distanceX > 0) {
                distanceXCount += distanceX;

                if (distanceXCount > 200) {
                    if (canMoveToRight()) {
                        //   Toast.makeText(getContext(), "滑倒最右侧了", Toast.LENGTH_SHORT).show();
                    } else {
                        moveRight();
                        distanceXCount = 0;
                        postInvalidate();
                    }
                }
            }

            if (distanceX < 0) {
                distanceXCount -= distanceX;

                if (distanceXCount > 200) {
                    if (canMoveToLeft()) {
                        //  Toast.makeText(getContext(), "滑倒最左侧了", Toast.LENGTH_SHORT).show();
                    } else {
                        moveLeft();
                        distanceXCount = 0;
                        postInvalidate();
                    }
                }
            }

            return false;
        }

        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            return false;
        }

        @Override
        public boolean onDoubleTap(MotionEvent e) {
            return true;
        }

        @Override
        public boolean onSingleTapConfirmed(MotionEvent e) {
            return true;
        }
    });

    /**********************************************************************************************/

    private List<? extends Entry> mEntryList;
    private int dotCount = 7;
    private int dotBegin;
    private int dotEnd;
    private int maxCount = 10;
    private int minCount = 7;
    private int segmentY = 5;

    public boolean isEmpty() {
        return null == mEntryList || mEntryList.size() == 0;
    }

    public void resteBoundaryValue() {

        if (isEmpty()) {
            dotEnd = 0;
            dotBegin = 0;
        } else if (mEntryList.size() <= dotCount) {
            dotEnd = mEntryList.size();
            dotBegin = 0;
        } else {
            dotEnd = mEntryList.size();
            dotBegin = dotEnd - dotCount;
        }
        // LogUtil.e("entry", "resteBoundaryValue ==> dotBegin = " + dotBegin + ", dotEnd = " + dotEnd + ", dotCountReal = " + (dotEnd - dotBegin));
    }

    public List<? extends Entry> getEntryList() {
        return mEntryList;
    }

    public void resetData() {
        if (null == mEntryList || mEntryList.isEmpty()) return;
        mEntryList = null;
        resteBoundaryValue();
    }

    public void addData(List<? extends Entry> mEntryList) {
        this.mEntryList = mEntryList;
        resteBoundaryValue();
    }

    public int getDotEnd() {
        return dotEnd;
    }

    public int getDotCountReal() {
        return dotEnd - dotBegin;
    }

    public boolean canMoveToLeft() {
        return dotBegin == 0;
    }

    public boolean canMoveToRight() {
        if (isEmpty()) return true;
        if (mEntryList.size() <= dotCount) return true;
        return dotEnd == mEntryList.size();
    }

    public int getDotBegin() {
        return dotBegin;
    }

    public int getMaxCount() {
        return maxCount;
    }

    public int getSegmentY() {
        return segmentY;
    }

    public void addDot() {
        this.dotCount += 1;
        resteBoundaryValue();
    }

    public void delDot() {
        this.dotCount -= 1;
        resteBoundaryValue();
    }

    public void moveLeft() {
        dotBegin -= 1;
        dotEnd -= 1;
    }

    public void moveRight() {
        dotBegin += 1;
        dotEnd += 1;
    }

    public boolean isMax() {

        if (isEmpty()) {
            return true;
        } else {

            if (mEntryList.size() <= dotCount) {
                return true;
            } else {
                int visableCount = dotEnd - dotBegin;
                return (maxCount == visableCount);
            }
        }
    }

    public boolean isMin() {

        boolean isMin = (minCount == (dotEnd - dotBegin));
        boolean isMax2 = ((null != mEntryList) && (mEntryList.size() <= minCount));

        return isMin || isMax2;
    }

    public int getDotCountDefault() {
        return dotCount;
    }

    public void notifyDataSetChanged(List<? extends Entry> entryData) {

        if (null == entryData) return;

        mHintText = mHintLoad;

        final ArrayList<Entry> list = new ArrayList<>();
        list.addAll(entryData);
        Collections.reverse(list);

        addData(list);
        postInvalidate();
    }

    /************************************************************************************/

    private final float dp2px(float dpValue) {
        final float scale = getContext().getResources().getDisplayMetrics().density;
        return dpValue * scale;
    }
}